///*
// * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
// * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// */
//
//package java.net;
//
//import java.io.Closeable;
//import java.io.File;
//import java.io.FilePermission;
//import java.io.IOException;
//import java.io.InputStream;
//import java.security.AccessControlContext;
//import java.security.AccessController;
//import java.security.CodeSigner;
//import java.security.CodeSource;
//import java.security.Permission;
//import java.security.PermissionCollection;
//import java.security.PrivilegedAction;
//import java.security.PrivilegedExceptionAction;
//import java.security.SecureClassLoader;
//import java.util.Enumeration;
//import java.util.List;
//import java.util.NoSuchElementException;
//import java.util.Objects;
//import java.util.Set;
//import java.util.WeakHashMap;
//import java.util.jar.Attributes;
//import java.util.jar.Attributes.Name;
//import java.util.jar.JarFile;
//import java.util.jar.Manifest;
//import sun.misc.Resource;
//import sun.misc.URLClassPath;
//import sun.net.www.ParseUtil;
//import sun.security.util.SecurityConstants;
//
///**
// * This class loader is used to load classes and resources from a search
// * path of URLs referring to both JAR files and directories. Any URL that
// * ends with a '/' is assumed to refer to a directory. Otherwise, the URL
// * is assumed to refer to a JAR file which will be opened as needed.
// * <p>
// * The AccessControlContext of the thread that created the instance of
// * URLClassLoader will be used when subsequently loading classes and
// * resources.
// * <p>
// * The classes that are loaded are by default granted permission only to
// * access the URLs specified when the URLClassLoader was created.
// *
// * @author  David Connelly
// * @since   1.2
// */
//public class URLClassLoader extends SecureClassLoader implements Closeable {
//    /* The search path for classes and resources */
//    private final URLClassPath ucp;
//
//    /* The context to be used when loading classes and resources */
//    private final AccessControlContext acc;
//
//    /**
//     * Constructs a new URLClassLoader for the given URLs. The URLs will be
//     * searched in the order specified for classes and resources after first
//     * searching in the specified parent class loader. Any URL that ends with
//     * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed
//     * to refer to a JAR file which will be downloaded and opened as needed.
//     *
//     * <p>If there is a security manager, this method first
//     * calls the security manager's {@code checkCreateClassLoader} method
//     * to ensure creation of a class loader is allowed.
//     *
//     * @param urls the URLs from which to load classes and resources
//     * @param parent the parent class loader for delegation
//     * @exception  SecurityException  if a security manager exists and its
//     *             {@code checkCreateClassLoader} method doesn't allow
//     *             creation of a class loader.
//     * @exception  NullPointerException if {@code urls} is {@code null}.
//     * @see SecurityManager#checkCreateClassLoader
//     */
//    public URLClassLoader(URL[] urls, ClassLoader parent) {
//        super(parent);
//        // this is to make the stack depth consistent with 1.1
//        SecurityManager security = System.getSecurityManager();
//        if (security != null) {
//            security.checkCreateClassLoader();
//        }
//        ucp = new URLClassPath(urls);
//        this.acc = AccessController.getContext();
//    }
//
//    URLClassLoader(URL[] urls, ClassLoader parent,
//                   AccessControlContext acc) {
//        super(parent);
//        // this is to make the stack depth consistent with 1.1
//        SecurityManager security = System.getSecurityManager();
//        if (security != null) {
//            security.checkCreateClassLoader();
//        }
//        ucp = new URLClassPath(urls);
//        this.acc = acc;
//    }
//
//    /**
//     * Constructs a new URLClassLoader for the specified URLs using the
//     * default delegation parent {@code ClassLoader}. The URLs will
//     * be searched in the order specified for classes and resources after
//     * first searching in the parent class loader. Any URL that ends with
//     * a '/' is assumed to refer to a directory. Otherwise, the URL is
//     * assumed to refer to a JAR file which will be downloaded and opened
//     * as needed.
//     *
//     * <p>If there is a security manager, this method first
//     * calls the security manager's {@code checkCreateClassLoader} method
//     * to ensure creation of a class loader is allowed.
//     *
//     * @param urls the URLs from which to load classes and resources
//     *
//     * @exception  SecurityException  if a security manager exists and its
//     *             {@code checkCreateClassLoader} method doesn't allow
//     *             creation of a class loader.
//     * @exception  NullPointerException if {@code urls} is {@code null}.
//     * @see SecurityManager#checkCreateClassLoader
//     */
//    public URLClassLoader(URL[] urls) {
//        super();
//        // this is to make the stack depth consistent with 1.1
//        SecurityManager security = System.getSecurityManager();
//        if (security != null) {
//            security.checkCreateClassLoader();
//        }
//        ucp = new URLClassPath(urls);
//        this.acc = AccessController.getContext();
//    }
//
//    URLClassLoader(URL[] urls, AccessControlContext acc) {
//        super();
//        // this is to make the stack depth consistent with 1.1
//        SecurityManager security = System.getSecurityManager();
//        if (security != null) {
//            security.checkCreateClassLoader();
//        }
//        ucp = new URLClassPath(urls);
//        this.acc = acc;
//    }
//
//    /**
//     * Constructs a new URLClassLoader for the specified URLs, parent
//     * class loader, and URLStreamHandlerFactory. The parent argument
//     * will be used as the parent class loader for delegation. The
//     * factory argument will be used as the stream handler factory to
//     * obtain protocol handlers when creating new jar URLs.
//     *
//     * <p>If there is a security manager, this method first
//     * calls the security manager's {@code checkCreateClassLoader} method
//     * to ensure creation of a class loader is allowed.
//     *
//     * @param urls the URLs from which to load classes and resources
//     * @param parent the parent class loader for delegation
//     * @param factory the URLStreamHandlerFactory to use when creating URLs
//     *
//     * @exception  SecurityException  if a security manager exists and its
//     *             {@code checkCreateClassLoader} method doesn't allow
//     *             creation of a class loader.
//     * @exception  NullPointerException if {@code urls} is {@code null}.
//     * @see SecurityManager#checkCreateClassLoader
//     */
//    public URLClassLoader(URL[] urls, ClassLoader parent,
//                          URLStreamHandlerFactory factory) {
//        super(parent);
//        // this is to make the stack depth consistent with 1.1
//        SecurityManager security = System.getSecurityManager();
//        if (security != null) {
//            security.checkCreateClassLoader();
//        }
//        ucp = new URLClassPath(urls, factory);
//        acc = AccessController.getContext();
//    }
//
//    /* A map (used as a set) to keep track of closeable local resources
//     * (either JarFiles or FileInputStreams). We don't care about
//     * Http resources since they don't need to be closed.
//     *
//     * If the resource is coming from a jar file
//     * we keep a (weak) reference to the JarFile object which can
//     * be closed if URLClassLoader.close() called. Due to jar file
//     * caching there will typically be only one JarFile object
//     * per underlying jar file.
//     *
//     * For file resources, which is probably a less common situation
//     * we have to keep a weak reference to each stream.
//     */
//
//    private WeakHashMap<Closeable,Void>
//        closeables = new WeakHashMap<>();
//
//    /**
//     * Returns an input stream for reading the specified resource.
//     * If this loader is closed, then any resources opened by this method
//     * will be closed.
//     *
//     * <p> The search order is described in the documentation for {@link
//     * #getResource(String)}.  </p>
//     *
//     * @param  name
//     *         The resource name
//     *
//     * @return  An input stream for reading the resource, or {@code null}
//     *          if the resource could not be found
//     *
//     * @since  1.7
//     */
//    public InputStream getResourceAsStream(String name) {
//        URL url = getResource(name);
//        try {
//            if (url == null) {
//                return null;
//            }
//            URLConnection urlc = url.openConnection();
//            InputStream is = urlc.getInputStream();
//            if (urlc instanceof JarURLConnection) {
//                JarURLConnection juc = (JarURLConnection)urlc;
//                JarFile jar = juc.getJarFile();
//                synchronized (closeables) {
//                    if (!closeables.containsKey(jar)) {
//                        closeables.put(jar, null);
//                    }
//                }
//            } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
//                synchronized (closeables) {
//                    closeables.put(is, null);
//                }
//            }
//            return is;
//        } catch (IOException e) {
//            return null;
//        }
//    }
//
//   /**
//    * Closes this URLClassLoader, so that it can no longer be used to load
//    * new classes or resources that are defined by this loader.
//    * Classes and resources defined by any of this loader's parents in the
//    * delegation hierarchy are still accessible. Also, any classes or resources
//    * that are already loaded, are still accessible.
//    * <p>
//    * In the case of jar: and file: URLs, it also closes any files
//    * that were opened by it. If another thread is loading a
//    * class when the {@code close} method is invoked, then the result of
//    * that load is undefined.
//    * <p>
//    * The method makes a best effort attempt to close all opened files,
//    * by catching {@link IOException}s internally. Unchecked exceptions
//    * and errors are not caught. Calling close on an already closed
//    * loader has no effect.
//    * <p>
//    * @exception IOException if closing any file opened by this class loader
//    * resulted in an IOException. Any such exceptions are caught internally.
//    * If only one is caught, then it is re-thrown. If more than one exception
//    * is caught, then the second and following exceptions are added
//    * as suppressed exceptions of the first one caught, which is then re-thrown.
//    *
//    * @exception SecurityException if a security manager is set, and it denies
//    *   {@link RuntimePermission}{@code ("closeClassLoader")}
//    *
//    * @since 1.7
//    */
//    public void close() throws IOException {
//        SecurityManager security = System.getSecurityManager();
//        if (security != null) {
//            security.checkPermission(new RuntimePermission("closeClassLoader"));
//        }
//        List<IOException> errors = ucp.closeLoaders();
//
//        // now close any remaining streams.
//
//        synchronized (closeables) {
//            Set<Closeable> keys = closeables.keySet();
//            for (Closeable c : keys) {
//                try {
//                    c.close();
//                } catch (IOException ioex) {
//                    errors.add(ioex);
//                }
//            }
//            closeables.clear();
//        }
//
//        if (errors.isEmpty()) {
//            return;
//        }
//
//        IOException firstex = errors.remove(0);
//
//        // Suppress any remaining exceptions
//
//        for (IOException error: errors) {
//            firstex.addSuppressed(error);
//        }
//        throw firstex;
//    }
//
//    /**
//     * Appends the specified URL to the list of URLs to search for
//     * classes and resources.
//     * <p>
//     * If the URL specified is {@code null} or is already in the
//     * list of URLs, or if this loader is closed, then invoking this
//     * method has no effect.
//     *
//     * @param url the URL to be added to the search path of URLs
//     */
//    protected void addURL(URL url) {
//        ucp.addURL(url);
//    }
//
//    /**
//     * Returns the search path of URLs for loading classes and resources.
//     * This includes the original list of URLs specified to the constructor,
//     * along with any URLs subsequently appended by the addURL() method.
//     * @return the search path of URLs for loading classes and resources.
//     */
//    public URL[] getURLs() {
//        return ucp.getURLs();
//    }
//
//    /**
//     * Finds and loads the class with the specified name from the URL search
//     * path. Any URLs referring to JAR files are loaded and opened as needed
//     * until the class is found.
//     *
//     * @param name the name of the class
//     * @return the resulting class
//     * @exception ClassNotFoundException if the class could not be found,
//     *            or if the loader is closed.
//     * @exception NullPointerException if {@code name} is {@code null}.
//     */
//    protected Class<?> findClass(final String name)
//        throws ClassNotFoundException
//    {
//        final Class<?> result;
//        try {
//            result = AccessController.doPrivileged(
//                new PrivilegedExceptionAction<Class<?>>() {
//                    public Class<?> run() throws ClassNotFoundException {
//                        String path = name.replace('.', '/').concat(".class");
//                        Resource res = ucp.getResource(path, false);
//                        if (res != null) {
//                            try {
//                                return defineClass(name, res);
//                            } catch (IOException e) {
//                                throw new ClassNotFoundException(name, e);
//                            }
//                        } else {
//                            return null;
//                        }
//                    }
//                }, acc);
//        } catch (java.security.PrivilegedActionException pae) {
//            throw (ClassNotFoundException) pae.getException();
//        }
//        if (result == null) {
//            throw new ClassNotFoundException(name);
//        }
//        return result;
//    }
//
//    /*
//     * Retrieve the package using the specified package name.
//     * If non-null, verify the package using the specified code
//     * source and manifest.
//     */
//    private Package getAndVerifyPackage(String pkgname,
//                                        Manifest man, URL url) {
//        Package pkg = getPackage(pkgname);
//        if (pkg != null) {
//            // Package found, so check package sealing.
//            if (pkg.isSealed()) {
//                // Verify that code source URL is the same.
//                if (!pkg.isSealed(url)) {
//                    throw new SecurityException(
//                        "sealing violation: package " + pkgname + " is sealed");
//                }
//            } else {
//                // Make sure we are not attempting to seal the package
//                // at this code source URL.
//                if ((man != null) && isSealed(pkgname, man)) {
//                    throw new SecurityException(
//                        "sealing violation: can't seal package " + pkgname +
//                        ": already loaded");
//                }
//            }
//        }
//        return pkg;
//    }
//
//    // Also called by VM to define Package for classes loaded from the CDS
//    // archive
//    private void definePackageInternal(String pkgname, Manifest man, URL url)
//    {
//        if (getAndVerifyPackage(pkgname, man, url) == null) {
//            try {
//                if (man != null) {
//                    definePackage(pkgname, man, url);
//                } else {
//                    definePackage(pkgname, null, null, null, null, null, null, null);
//                }
//            } catch (IllegalArgumentException iae) {
//                // parallel-capable class loaders: re-verify in case of a
//                // race condition
//                if (getAndVerifyPackage(pkgname, man, url) == null) {
//                    // Should never happen
//                    throw new AssertionError("Cannot find package " +
//                                             pkgname);
//                }
//            }
//        }
//    }
//
//    /*
//     * Defines a Class using the class bytes obtained from the specified
//     * Resource. The resulting Class must be resolved before it can be
//     * used.
//     */
//    private Class<?> defineClass(String name, Resource res) throws IOException {
//        long t0 = System.nanoTime();
//        int i = name.lastIndexOf('.');
//        URL url = res.getCodeSourceURL();
//        if (i != -1) {
//            String pkgname = name.substring(0, i);
//            // Check if package already loaded.
//            Manifest man = res.getManifest();
//            definePackageInternal(pkgname, man, url);
//        }
//        // Now read the class bytes and define the class
//        java.nio.ByteBuffer bb = res.getByteBuffer();
//        if (bb != null) {
//            // Use (direct) ByteBuffer:
//            CodeSigner[] signers = res.getCodeSigners();
//            CodeSource cs = new CodeSource(url, signers);
//            sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
//            return defineClass(name, bb, cs);
//        } else {
//            byte[] b = res.getBytes();
//            // must read certificates AFTER reading bytes.
//            CodeSigner[] signers = res.getCodeSigners();
//            CodeSource cs = new CodeSource(url, signers);
//            sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
//            return defineClass(name, b, 0, b.length, cs);
//        }
//    }
//
//    /**
//     * Defines a new package by name in this ClassLoader. The attributes
//     * contained in the specified Manifest will be used to obtain package
//     * version and sealing information. For sealed packages, the additional
//     * URL specifies the code source URL from which the package was loaded.
//     *
//     * @param name  the package name
//     * @param man   the Manifest containing package version and sealing
//     *              information
//     * @param url   the code source url for the package, or null if none
//     * @exception   IllegalArgumentException if the package name duplicates
//     *              an existing package either in this class loader or one
//     *              of its ancestors
//     * @return the newly defined Package object
//     */
//    protected Package definePackage(String name, Manifest man, URL url)
//        throws IllegalArgumentException
//    {
//        String path = name.replace('.', '/').concat("/");
//        String specTitle = null, specVersion = null, specVendor = null;
//        String implTitle = null, implVersion = null, implVendor = null;
//        String sealed = null;
//        URL sealBase = null;
//
//        Attributes attr = man.getAttributes(path);
//        if (attr != null) {
//            specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
//            specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
//            specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
//            implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
//            implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
//            implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
//            sealed      = attr.getValue(Name.SEALED);
//        }
//        attr = man.getMainAttributes();
//        if (attr != null) {
//            if (specTitle == null) {
//                specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
//            }
//            if (specVersion == null) {
//                specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
//            }
//            if (specVendor == null) {
//                specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
//            }
//            if (implTitle == null) {
//                implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
//            }
//            if (implVersion == null) {
//                implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
//            }
//            if (implVendor == null) {
//                implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
//            }
//            if (sealed == null) {
//                sealed = attr.getValue(Name.SEALED);
//            }
//        }
//        if ("true".equalsIgnoreCase(sealed)) {
//            sealBase = url;
//        }
//        return definePackage(name, specTitle, specVersion, specVendor,
//                             implTitle, implVersion, implVendor, sealBase);
//    }
//
//    /*
//     * Returns true if the specified package name is sealed according to the
//     * given manifest.
//     */
//    private boolean isSealed(String name, Manifest man) {
//        String path = name.replace('.', '/').concat("/");
//        Attributes attr = man.getAttributes(path);
//        String sealed = null;
//        if (attr != null) {
//            sealed = attr.getValue(Name.SEALED);
//        }
//        if (sealed == null) {
//            if ((attr = man.getMainAttributes()) != null) {
//                sealed = attr.getValue(Name.SEALED);
//            }
//        }
//        return "true".equalsIgnoreCase(sealed);
//    }
//
//    /**
//     * Finds the resource with the specified name on the URL search path.
//     *
//     * @param name the name of the resource
//     * @return a {@code URL} for the resource, or {@code null}
//     * if the resource could not be found, or if the loader is closed.
//     */
//    public URL findResource(final String name) {
//        /*
//         * The same restriction to finding classes applies to resources
//         */
//        URL url = AccessController.doPrivileged(
//            new PrivilegedAction<URL>() {
//                public URL run() {
//                    return ucp.findResource(name, true);
//                }
//            }, acc);
//
//        return url != null ? ucp.checkURL(url) : null;
//    }
//
//    /**
//     * Returns an Enumeration of URLs representing all of the resources
//     * on the URL search path having the specified name.
//     *
//     * @param name the resource name
//     * @exception IOException if an I/O exception occurs
//     * @return an {@code Enumeration} of {@code URL}s
//     *         If the loader is closed, the Enumeration will be empty.
//     */
//    public Enumeration<URL> findResources(final String name)
//        throws IOException
//    {
//        final Enumeration<URL> e = ucp.findResources(name, true);
//
//        return new Enumeration<URL>() {
//            private URL url = null;
//
//            private boolean next() {
//                if (url != null) {
//                    return true;
//                }
//                do {
//                    URL u = AccessController.doPrivileged(
//                        new PrivilegedAction<URL>() {
//                            public URL run() {
//                                if (!e.hasMoreElements())
//                                    return null;
//                                return e.nextElement();
//                            }
//                        }, acc);
//                    if (u == null)
//                        break;
//                    url = ucp.checkURL(u);
//                } while (url == null);
//                return url != null;
//            }
//
//            public URL nextElement() {
//                if (!next()) {
//                    throw new NoSuchElementException();
//                }
//                URL u = url;
//                url = null;
//                return u;
//            }
//
//            public boolean hasMoreElements() {
//                return next();
//            }
//        };
//    }
//
//    /**
//     * Returns the permissions for the given codesource object.
//     * The implementation of this method first calls super.getPermissions
//     * and then adds permissions based on the URL of the codesource.
//     * <p>
//     * If the protocol of this URL is "jar", then the permission granted
//     * is based on the permission that is required by the URL of the Jar
//     * file.
//     * <p>
//     * If the protocol is "file" and there is an authority component, then
//     * permission to connect to and accept connections from that authority
//     * may be granted. If the protocol is "file"
//     * and the path specifies a file, then permission to read that
//     * file is granted. If protocol is "file" and the path is
//     * a directory, permission is granted to read all files
//     * and (recursively) all files and subdirectories contained in
//     * that directory.
//     * <p>
//     * If the protocol is not "file", then permission
//     * to connect to and accept connections from the URL's host is granted.
//     * @param codesource the codesource
//     * @exception NullPointerException if {@code codesource} is {@code null}.
//     * @return the permissions granted to the codesource
//     */
//    protected PermissionCollection getPermissions(CodeSource codesource)
//    {
//        PermissionCollection perms = super.getPermissions(codesource);
//
//        URL url = codesource.getLocation();
//
//        Permission p;
//        URLConnection urlConnection;
//
//        try {
//            urlConnection = url.openConnection();
//            p = urlConnection.getPermission();
//        } catch (java.io.IOException ioe) {
//            p = null;
//            urlConnection = null;
//        }
//
//        if (p instanceof FilePermission) {
//            // if the permission has a separator char on the end,
//            // it means the codebase is a directory, and we need
//            // to add an additional permission to read recursively
//            String path = p.getName();
//            if (path.endsWith(File.separator)) {
//                path += "-";
//                p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
//            }
//        } else if ((p == null) && (url.getProtocol().equals("file"))) {
//            String path = url.getFile().replace('/', File.separatorChar);
//            path = ParseUtil.decode(path);
//            if (path.endsWith(File.separator))
//                path += "-";
//            p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
//        } else {
//            /**
//             * Not loading from a 'file:' URL so we want to give the class
//             * permission to connect to and accept from the remote host
//             * after we've made sure the host is the correct one and is valid.
//             */
//            URL locUrl = url;
//            if (urlConnection instanceof JarURLConnection) {
//                locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
//            }
//            String host = locUrl.getHost();
//            if (host != null && (host.length() > 0))
//                p = new SocketPermission(host,
//                                         SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
//        }
//
//        // make sure the person that created this class loader
//        // would have this permission
//
//        if (p != null) {
//            final SecurityManager sm = System.getSecurityManager();
//            if (sm != null) {
//                final Permission fp = p;
//                AccessController.doPrivileged(new PrivilegedAction<Void>() {
//                    public Void run() throws SecurityException {
//                        sm.checkPermission(fp);
//                        return null;
//                    }
//                }, acc);
//            }
//            perms.add(p);
//        }
//        return perms;
//    }
//
//    /**
//     * Creates a new instance of URLClassLoader for the specified
//     * URLs and parent class loader. If a security manager is
//     * installed, the {@code loadClass} method of the URLClassLoader
//     * returned by this method will invoke the
//     * {@code SecurityManager.checkPackageAccess} method before
//     * loading the class.
//     *
//     * @param urls the URLs to search for classes and resources
//     * @param parent the parent class loader for delegation
//     * @exception  NullPointerException if {@code urls} is {@code null}.
//     * @return the resulting class loader
//     */
//    public static URLClassLoader newInstance(final URL[] urls,
//                                             final ClassLoader parent) {
//        // Save the caller's context
//        final AccessControlContext acc = AccessController.getContext();
//        // Need a privileged block to create the class loader
//        URLClassLoader ucl = AccessController.doPrivileged(
//            new PrivilegedAction<URLClassLoader>() {
//                public URLClassLoader run() {
//                    return new FactoryURLClassLoader(urls, parent, acc);
//                }
//            });
//        return ucl;
//    }
//
//    /**
//     * Creates a new instance of URLClassLoader for the specified
//     * URLs and default parent class loader. If a security manager is
//     * installed, the {@code loadClass} method of the URLClassLoader
//     * returned by this method will invoke the
//     * {@code SecurityManager.checkPackageAccess} before
//     * loading the class.
//     *
//     * @param urls the URLs to search for classes and resources
//     * @exception  NullPointerException if {@code urls} is {@code null}.
//     * @return the resulting class loader
//     */
//    public static URLClassLoader newInstance(final URL[] urls) {
//        // Save the caller's context
//        final AccessControlContext acc = AccessController.getContext();
//        // Need a privileged block to create the class loader
//        URLClassLoader ucl = AccessController.doPrivileged(
//            new PrivilegedAction<URLClassLoader>() {
//                public URLClassLoader run() {
//                    return new FactoryURLClassLoader(urls, acc);
//                }
//            });
//        return ucl;
//    }
//
//    static {
//        sun.misc.SharedSecrets.setJavaNetAccess (
//            new sun.misc.JavaNetAccess() {
//                public URLClassPath getURLClassPath (URLClassLoader u) {
//                    return u.ucp;
//                }
//
//                public String getOriginalHostName(InetAddress ia) {
//                    return ia.holder.getOriginalHostName();
//                }
//            }
//        );
//        ClassLoader.registerAsParallelCapable();
//    }
//}
//
//final class FactoryURLClassLoader extends URLClassLoader {
//
//    static {
//        ClassLoader.registerAsParallelCapable();
//    }
//
//    FactoryURLClassLoader(URL[] urls, ClassLoader parent,
//                          AccessControlContext acc) {
//        super(urls, parent, acc);
//    }
//
//    FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
//        super(urls, acc);
//    }
//
//    public final Class<?> loadClass(String name, boolean resolve)
//        throws ClassNotFoundException
//    {
//        // First check if we have permission to access the package. This
//        // should go away once we've added support for exported packages.
//        SecurityManager sm = System.getSecurityManager();
//        if (sm != null) {
//            int i = name.lastIndexOf('.');
//            if (i != -1) {
//                sm.checkPackageAccess(name.substring(0, i));
//            }
//        }
//        return super.loadClass(name, resolve);
//    }
//}
